From 4816a2a5d8544c718123ac9a8e66175abc24a40f Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Wed, 9 Sep 2015 14:16:43 +0530 Subject: [PATCH] Add `cargo rustdoc` for passing arbitrary flags to rustdoc --- src/bin/bench.rs | 1 + src/bin/build.rs | 1 + src/bin/cargo.rs | 1 + src/bin/doc.rs | 1 + src/bin/run.rs | 1 + src/bin/rustc.rs | 1 + src/bin/rustdoc.rs | 89 ++++++++++++++++ src/bin/test.rs | 1 + src/cargo/core/manifest.rs | 2 + src/cargo/ops/cargo_compile.rs | 21 ++++ src/cargo/ops/cargo_package.rs | 1 + src/cargo/ops/cargo_rustc/mod.rs | 5 + src/cargo/util/toml.rs | 1 + tests/test_cargo_rustdoc.rs | 178 +++++++++++++++++++++++++++++++ tests/tests.rs | 1 + 15 files changed, 305 insertions(+) create mode 100644 src/bin/rustdoc.rs create mode 100644 tests/test_cargo_rustdoc.rs diff --git a/src/bin/bench.rs b/src/bin/bench.rs index 7e658997d..47f5b9a93 100644 --- a/src/bin/bench.rs +++ b/src/bin/bench.rs @@ -84,6 +84,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), + extra_rustdoc_args: Vec::new(), target_rustc_args: None, }, }; diff --git a/src/bin/build.rs b/src/bin/build.rs index 27bcf57b1..92971e77d 100644 --- a/src/bin/build.rs +++ b/src/bin/build.rs @@ -81,6 +81,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), + extra_rustdoc_args: Vec::new(), target_rustc_args: None, }; diff --git a/src/bin/cargo.rs b/src/bin/cargo.rs index 144e020a0..3c3167828 100644 --- a/src/bin/cargo.rs +++ b/src/bin/cargo.rs @@ -81,6 +81,7 @@ macro_rules! each_subcommand{ ($mac:ident) => ({ $mac!(read_manifest); $mac!(run); $mac!(rustc); + $mac!(rustdoc); $mac!(search); $mac!(test); $mac!(uninstall); diff --git a/src/bin/doc.rs b/src/bin/doc.rs index 16fd12430..0ac61d6bd 100644 --- a/src/bin/doc.rs +++ b/src/bin/doc.rs @@ -70,6 +70,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { deps: !options.flag_no_deps, }, target_rustc_args: None, + extra_rustdoc_args: Vec::new(), }, }; diff --git a/src/bin/run.rs b/src/bin/run.rs index d765967dd..d74b5d457 100644 --- a/src/bin/run.rs +++ b/src/bin/run.rs @@ -80,6 +80,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { bins: &bins, examples: &examples, } }, + extra_rustdoc_args: Vec::new(), target_rustc_args: None, }; diff --git a/src/bin/rustc.rs b/src/bin/rustc.rs index 924cfb636..78a17dada 100644 --- a/src/bin/rustc.rs +++ b/src/bin/rustc.rs @@ -84,6 +84,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), + extra_rustdoc_args: Vec::new(), target_rustc_args: options.arg_opts.as_ref().map(|a| &a[..]), }; diff --git a/src/bin/rustdoc.rs b/src/bin/rustdoc.rs new file mode 100644 index 000000000..181cbf8a9 --- /dev/null +++ b/src/bin/rustdoc.rs @@ -0,0 +1,89 @@ +use cargo::ops; +use cargo::util::{CliResult, CliError, Config}; +use cargo::util::important_paths::{find_root_manifest_for_cwd}; + +#[derive(RustcDecodable)] +struct Options { + arg_opts: Vec, + flag_target: Option, + flag_features: Vec, + flag_jobs: Option, + flag_manifest_path: Option, + flag_no_default_features: bool, + flag_no_deps: bool, + flag_open: bool, + flag_verbose: bool, + flag_release: bool, + flag_quiet: bool, + flag_color: Option, + flag_package: Option, +} + +pub const USAGE: &'static str = " +Build a package's documentation, using specified custom flags. + +Usage: + cargo rustdoc [options] [--] [...] + +Options: + -h, --help Print this message + --open Opens the docs in a browser after the operation + -p SPEC, --package SPEC Package to document + --no-deps Don't build documentation for dependencies + -j N, --jobs N The number of jobs to run in parallel + --release Build artifacts in release mode, with optimizations + --features FEATURES Space-separated list of features to also build + --no-default-features Do not build the `default` feature + --target TRIPLE Build for the target triple + --manifest-path PATH Path to the manifest to document + -v, --verbose Use verbose output + -q, --quiet No output printed to stdout + --color WHEN Coloring: auto, always, never + +By default the documentation for the local package and all dependencies is +built. The output is all placed in `target/doc` in rustdoc's usual format. + +The specified target for the current package (or package specified by SPEC if +provided) will be documented along with all of its dependencies. The specified +... will all be passed to the final rustdoc invocation, not any of the +dependencies. Note that rustdoc will still unconditionally receive +arguments such as -L, --extern, and --crate-type, and the specified ... +will simply be added to the rustdoc invocation. + +If the --package argument is given, then SPEC is a package id specification +which indicates which package should be documented. If it is not given, then the +current package is documented. For more information on SPEC and its format, see +the `cargo help pkgid` command. +"; + +pub fn execute(options: Options, config: &Config) -> CliResult> { + try!(config.shell().set_verbosity(options.flag_verbose, options.flag_quiet)); + try!(config.shell().set_color_config(options.flag_color.as_ref().map(|s| &s[..]))); + + let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path)); + + let mut doc_opts = ops::DocOptions { + open_result: options.flag_open, + compile_opts: ops::CompileOptions { + config: config, + jobs: options.flag_jobs, + target: options.flag_target.as_ref().map(|t| &t[..]), + features: &options.flag_features, + no_default_features: options.flag_no_default_features, + spec: options.flag_package.as_ref().map(|s| &s[..]), + exec_engine: None, + filter: ops::CompileFilter::Everything, + release: options.flag_release, + mode: ops::CompileMode::Doc { + deps: !options.flag_no_deps, + }, + extra_rustdoc_args: options.arg_opts, + target_rustc_args: None, + }, + }; + + try!(ops::doc(&root, &mut doc_opts).map_err(|err| CliError::from_boxed(err, 101))); + + Ok(None) +} + diff --git a/src/bin/test.rs b/src/bin/test.rs index 09981e0be..16c3e1fb3 100644 --- a/src/bin/test.rs +++ b/src/bin/test.rs @@ -90,6 +90,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { &options.flag_test, &options.flag_example, &options.flag_bench), + extra_rustdoc_args: Vec::new(), target_rustc_args: None, }, }; diff --git a/src/cargo/core/manifest.rs b/src/cargo/core/manifest.rs index 68f3d2d4c..ef9fa5433 100644 --- a/src/cargo/core/manifest.rs +++ b/src/cargo/core/manifest.rs @@ -112,6 +112,7 @@ pub struct Profile { pub lto: bool, pub codegen_units: Option, // None = use rustc default pub rustc_args: Option>, + pub rustdoc_args: Option>, pub debuginfo: bool, pub debug_assertions: bool, pub rpath: bool, @@ -474,6 +475,7 @@ impl Default for Profile { lto: false, codegen_units: None, rustc_args: None, + rustdoc_args: None, debuginfo: false, debug_assertions: false, rpath: false, diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs index 547aa8d37..0484d8023 100644 --- a/src/cargo/ops/cargo_compile.rs +++ b/src/cargo/ops/cargo_compile.rs @@ -57,6 +57,8 @@ pub struct CompileOptions<'a> { pub release: bool, /// Mode for this compile. pub mode: CompileMode, + /// Extra arguments to be passed to rustdoc (for main crate and dependencies) + pub extra_rustdoc_args: Vec, /// The specified target will be compiled with all the available arguments, /// note that this only accounts for the *final* invocation of rustc pub target_rustc_args: Option<&'a [String]>, @@ -145,6 +147,7 @@ pub fn compile_pkg<'a>(root_package: &Package, let CompileOptions { config, jobs, target, spec, features, no_default_features, release, mode, ref filter, ref exec_engine, + ref extra_rustdoc_args, ref target_rustc_args } = *options; let target = target.map(|s| s.to_string()); @@ -223,6 +226,24 @@ pub fn compile_pkg<'a>(root_package: &Package, } let mut ret = { + let mut target_with_rustdoc = None; + if !extra_rustdoc_args.is_empty() { + let mut target_with_rustdoc_inner = Vec::new(); + for &(target, profile) in &targets { + if profile.doc { + let mut profile = profile.clone(); + profile.rustdoc_args = Some(extra_rustdoc_args.clone()); + target_with_rustdoc_inner.push((target, profile)); + } + } + target_with_rustdoc = Some(target_with_rustdoc_inner); + }; + + let targets = target_with_rustdoc.as_ref().map_or(targets, + |o| o.into_iter() + .map(|&(t, ref p)| (t, p)) + .collect()); + let ret = { let _p = profile::start("compiling"); let mut build_config = try!(scrape_build_config(config, jobs, target)); build_config.exec_engine = exec_engine.clone(); diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index 635aaf5c3..45b966b59 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -220,6 +220,7 @@ fn run_verify(config: &Config, pkg: &Package, tar: &Path) exec_engine: None, release: false, mode: ops::CompileMode::Build, + extra_rustdoc_args: Vec::new(), target_rustc_args: None, })); diff --git a/src/cargo/ops/cargo_rustc/mod.rs b/src/cargo/ops/cargo_rustc/mod.rs index 5feb33591..2b738bc94 100644 --- a/src/cargo/ops/cargo_rustc/mod.rs +++ b/src/cargo/ops/cargo_rustc/mod.rs @@ -395,6 +395,10 @@ fn rustdoc(cx: &mut Context, unit: &Unit) -> CargoResult { } } + if let Some(ref args) = profile.rustdoc_args { + rustdoc.args(args); + } + try!(build_deps_args(&mut rustdoc, cx, unit)); if unit.pkg.has_custom_build() { @@ -448,6 +452,7 @@ fn build_base_args(cx: &Context, let Profile { opt_level, lto, codegen_units, ref rustc_args, debuginfo, debug_assertions, rpath, test, doc: _doc, run_custom_build, + rustdoc_args: _, } = *unit.profile; assert!(!run_custom_build); diff --git a/src/cargo/util/toml.rs b/src/cargo/util/toml.rs index 430bdde9a..85a7befc0 100644 --- a/src/cargo/util/toml.rs +++ b/src/cargo/util/toml.rs @@ -941,6 +941,7 @@ fn build_profiles(profiles: &Option) -> Profiles { lto: lto.unwrap_or(profile.lto), codegen_units: codegen_units, rustc_args: None, + rustdoc_args: None, debuginfo: debug.unwrap_or(profile.debuginfo), debug_assertions: debug_assertions.unwrap_or(profile.debug_assertions), rpath: rpath.unwrap_or(profile.rpath), diff --git a/tests/test_cargo_rustdoc.rs b/tests/test_cargo_rustdoc.rs new file mode 100644 index 000000000..775051ffc --- /dev/null +++ b/tests/test_cargo_rustdoc.rs @@ -0,0 +1,178 @@ +use std::path::MAIN_SEPARATOR as SEP; +use support::{execs, project}; +use support::{COMPILING, RUNNING}; +use hamcrest::{assert_that}; + +fn setup() { +} + + +test!(rustdoc_simple { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", r#" "#); + + assert_that(p.cargo_process("rustdoc").arg("-v"), + execs() + .with_status(0) + .with_stdout(format!("\ +{compiling} foo v0.0.1 ({url}) +{running} `rustdoc src{sep}lib.rs --crate-name foo \ + -o {dir}{sep}target{sep}doc \ + -L dependency={dir}{sep}target{sep}debug \ + -L dependency={dir}{sep}target{sep}debug{sep}deps` +", + running = RUNNING, compiling = COMPILING, sep = SEP, + dir = p.root().display(), url = p.url()))); +}); + +test!(rustdoc_args { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", r#" "#); + + assert_that(p.cargo_process("rustdoc").arg("-v").arg("--").arg("--no-defaults"), + execs() + .with_status(0) + .with_stdout(format!("\ +{compiling} foo v0.0.1 ({url}) +{running} `rustdoc src{sep}lib.rs --crate-name foo \ + -o {dir}{sep}target{sep}doc \ + --no-defaults \ + -L dependency={dir}{sep}target{sep}debug \ + -L dependency={dir}{sep}target{sep}debug{sep}deps` +", + running = RUNNING, compiling = COMPILING, sep = SEP, + dir = p.root().display(), url = p.url()))); +}); + + + +test!(rustdoc_foo_with_bar_dependency { + let foo = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.bar] + path = "../bar" + "#) + .file("src/lib.rs", r#" + extern crate bar; + pub fn foo() {} + "#); + let bar = project("bar") + .file("Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", r#" + pub fn baz() {} + "#); + bar.build(); + + assert_that(foo.cargo_process("rustdoc").arg("-v").arg("--").arg("--no-defaults"), + execs() + .with_status(0) + .with_stdout(format!("\ +{compiling} bar v0.0.1 ({url}) +{running} `rustc {bar_dir}{sep}src{sep}lib.rs [..]` +{running} `rustdoc {bar_dir}{sep}src{sep}lib.rs --crate-name bar \ + -o {dir}{sep}target{sep}doc \ + -L dependency={dir}{sep}target{sep}debug{sep}deps \ + -L dependency={dir}{sep}target{sep}debug{sep}deps` +{compiling} foo v0.0.1 ({url}) +{running} `rustdoc src{sep}lib.rs --crate-name foo \ + -o {dir}{sep}target{sep}doc \ + --no-defaults \ + -L dependency={dir}{sep}target{sep}debug \ + -L dependency={dir}{sep}target{sep}debug{sep}deps \ + --extern [..]` +", + running = RUNNING, compiling = COMPILING, sep = SEP, + dir = foo.root().display(), url = foo.url(), + bar_dir = bar.root().display()))); +}); + +test!(rustdoc_only_bar_dependency { + let foo = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.bar] + path = "../bar" + "#) + .file("src/main.rs", r#" + extern crate bar; + fn main() { + bar::baz() + } + "#); + let bar = project("bar") + .file("Cargo.toml", r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + "#) + .file("src/lib.rs", r#" + pub fn baz() {} + "#); + bar.build(); + + assert_that(foo.cargo_process("rustdoc").arg("-v").arg("-p").arg("bar") + .arg("--").arg("--no-defaults"), + execs() + .with_status(0) + .with_stdout(format!("\ +{compiling} bar v0.0.1 ({url}) +{running} `rustdoc {bar_dir}{sep}src{sep}lib.rs --crate-name bar \ + -o {dir}{sep}target{sep}doc \ + --no-defaults \ + -L dependency={dir}{sep}target{sep}debug{sep}deps \ + -L dependency={dir}{sep}target{sep}debug{sep}deps` +", + running = RUNNING, compiling = COMPILING, sep = SEP, + dir = foo.root().display(), url = foo.url(), + bar_dir = bar.root().display()))); +}); + + +test!(rustdoc_same_name_err { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + "#) + .file("src/main.rs", r#" + fn main() {} + "#) + .file("src/lib.rs", r#" "#); + + assert_that(p.cargo_process("rustdoc").arg("-v") + .arg("--").arg("--no-defaults"), + execs() + .with_status(101) + .with_stderr("Cannot document a package where a library and a \ + binary have the same name. Consider renaming one \ + or marking the target as `doc = false`")); +}); diff --git a/tests/tests.rs b/tests/tests.rs index 612d11e03..19aaf0aff 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -57,6 +57,7 @@ mod test_cargo_read_manifest; mod test_cargo_registry; mod test_cargo_run; mod test_cargo_rustc; +mod test_cargo_rustdoc; mod test_cargo_search; mod test_cargo_test; mod test_cargo_tool_paths; -- 2.30.2